/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.sdt;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import java.util.Vector;
import edu.yonsei.iwb.sdt.algorithm.DCSSearcher;
import edu.yonsei.iwb.sdt.algorithm.TreeDecomposer;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import edu.yonsei.iwb.sdt.datastructure.TargetInstance;
import edu.yonsei.iwb.sdt.datastructure.tree.DEdge;
import edu.yonsei.iwb.sdt.datastructure.tree.DNode;
import edu.yonsei.iwb.sdt.datastructure.rule.DecisionRule;
import edu.yonsei.iwb.sdt.datastructure.tree.NodeType;
import edu.yonsei.iwb.sdt.datastructure.TargetInstanceSet;
import edu.yonsei.iwb.sdt.datastructure.rule.DecisionRuleSet;
import edu.yonsei.iwb.sdt.datastructure.rule.DecisionRuleComponent;
import edu.yonsei.iwb.sdt.guix.GDLearningPanel;
import edu.yonsei.iwb.sdt.guix.GraphDataLearner;
import edu.yonsei.iwb.sdt.ontology.ClassModel;
import edu.yonsei.iwb.sdt.ontology.OntologyModel;
import edu.yonsei.iwb.sdt.ontology.PropertyArc;
import edu.yonsei.iwb.sdt.ontology.UncountedResources;
import edu.yonsei.iwb.sdt.util.SDTLog;
import edu.yonsei.iwb.ts.TSSearch;
import edu.yonsei.iwb.ts.model.ObjectNode;
import edu.yonsei.iwb.ts.model.Triple;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Hashtable;

/**
 *
 * @author JDK
 */
public class SDTLearner {

    private String targetClass;
    public static String TARGETPROPERTY;
    private Vector<String> targetInstances;
    private int learningOption;
    private Model model;
    private ClassModel classmodel;
    private TargetInstanceSet targetinstSet;
    private Vector<TargetInstance> instanceSet;
    private DNode root;
    private DecomposeCandidateSet dcs;
    private DecisionRuleSet ners;
    private UncountedResources ur;
    
    private int[] candNumArray;
    
    public static int NODE_ID = 0;
    public static int TARGETVALUESIZE = 2;
    public static int LEAFSIZE = 2;
    public static int EXPAND_DEPTH = 1;
    public static int PRESENT_DEPTH = 0;
    private double ENTROPY_THRESHOLD = 0.6;
    public static double SELECTRATE;

    public SDTLearner(String targetClass, String targetProperty, ArrayList<String> insset, ArrayList<Integer> vset, double sr) throws IOException {
        System.out.println("# SDT Learner Initializing...." + " - ["+Calendar.getInstance().getTime()+"]");
        this.classmodel = new ClassModel();
        this.classmodel.classModelMaker();
        this.targetClass = targetClass;
        SDTLearner.TARGETPROPERTY = targetProperty;
        SDTLearner.SELECTRATE = sr;
        this.targetinstSet = new TargetInstanceSet();
        this.ners = new DecisionRuleSet();

        ArrayList<String> valueSet = this.generateValueSet(insset, vset);        
        System.out.println("# Target Instance Value loading complete..." + " - ["+Calendar.getInstance().getTime()+"]");
        
        SDTLearner.TARGETVALUESIZE = valueSet.size();        
        this.targetinstSet.setTargetInstanceValueSet(valueSet);        
//        this.targetinstSet.printTargetInstanceSet();

        this.instanceSet = this.targetinstSet.getInstanceList();
        this.root = new DNode(this.instanceSet, "root");
        this.ur = new UncountedResources();
    }

    public DNode learningStart() throws IOException {
        dcs = new DecomposeCandidateSet();
        DCSSearcher sdcs = new DCSSearcher(this.classmodel, this.learningOption);
        TreeDecomposer td = new TreeDecomposer(this.classmodel, this.learningOption, this.targetinstSet, this.ENTROPY_THRESHOLD);

        long startTime = System.currentTimeMillis();
        dcs.setTargetclass(targetClass);
        sdcs.searchDecomposeCandidateSet(dcs, this.instanceSet, new Vector<PropertyArc>());
        this.root.setTargetValueInstanceInformation(targetinstSet);
        this.root.setEntropy();
        td.decomposeTreeNode(this.root, dcs);                
        long endTime = System.currentTimeMillis();
        
        this.candNumArray = new int[]{td.getMinCandidateNumber(),td.getMaxCandidateNumber()};
        System.out.println("\nRunning Time = " + (endTime - startTime) / 1000.0f + " sec");

//        this.printNode(this.root);
//        this.showTree(root);
        return this.root;
    }
    
    public int[] getCandNumArray(){
        return this.candNumArray;
    }
        
    private ArrayList<String> generateValueSet(ArrayList<String> insset, ArrayList<Integer> vset) throws IOException{
        ArrayList<String> valueSet = new ArrayList();
        for (int i = 0; i < insset.size(); i++) {
            String targetins = insset.get(i);
            int value = vset.get(i);
            this.targetinstSet.putTI(new TargetInstance("i_" + i, targetins), value);
            if(!valueSet.contains(""+value)){
                valueSet.add(""+value);
            }            
//            System.out.println(i + " targetins: " + targetins + " / value: " + value);
        }             
        return valueSet;
    }

    private ArrayList<String> generateValueSet(ArrayList<String> insset, boolean index) throws IOException {
        ArrayList<String> valueSet = new ArrayList();
        ArrayList<Triple> obset = TSSearch.listTriple(null, SDTLearner.TARGETPROPERTY, null);
        Hashtable<String, Integer> obtable = new Hashtable();
        for (int i = 0; i < obset.size(); i++) {
            Triple triple = obset.get(i);
            String su = triple.getSubject();
            int value = Integer.parseInt(triple.getObject().getValue());
            obtable.put(su, value);
        }

        for (int j = 0; j < insset.size(); j++) {
            String targetins = insset.get(j);
            int value = obtable.get(targetins);
//            System.out.println(j + " targetins: " + targetins + " / value: " + value);
            if (value < 2) {
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), 0);
            } else if (value >= 2 && value < 4) {
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), 1);
            } else if (value >= 4 && value < 6) {
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), 2);
            } else if (value >= 6 && value < 8) {
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), 3);
            } else if (value >= 8) {
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), 4);
            }
        }
        valueSet.add("" + 0);
        valueSet.add("" + 1);
        valueSet.add("" + 2);
        valueSet.add("" + 3);
        valueSet.add("" + 4);
        return valueSet;
    }

    private ArrayList<String> generateValueSet(ArrayList<String> insset) throws IOException {
        ArrayList<String> valueSet = new ArrayList();
        for (int j = 0; j < insset.size(); j++) {
            String targetins = insset.get(j);
            ArrayList<ObjectNode> obset = TSSearch.listObjectNode(targetins, SDTLearner.TARGETPROPERTY);
            for (int i = 0; i < obset.size(); i++) {
                ObjectNode objectNode = obset.get(i);
                String value = objectNode.getValue();
                if (!valueSet.contains(value)) {
                    valueSet.add(value);
                }
                this.targetinstSet.putTI(new TargetInstance("i_" + j, targetins), valueSet.indexOf(value));
            }
        }
        return valueSet;
    }

    @Deprecated
    public SDTLearner(String targetClass, String targetProperty, OntologyModel ontmodel, int learningOption) {
//        this.model = ontmodel.getJenaModel();
//        this.learningOption = learningOption;
//        this.targetClass = this.model.getResource(targetClass);
//        this.classmodel = new ClassModel();
//        this.ners = new DecisionRuleSet();
//        SDTLearner.TARGETPROPERTY = model.getProperty(targetProperty);        
//
//        Vector<RDFNode> valueSet = new Vector<RDFNode>();
////        TargetInstanceValueSet tivs = new TargetInstanceValueSet();
//        this.targetinstSet = new TargetInstanceSet();
//        
//        ResIterator res = this.model.listResourcesWithProperty(RDF.type, this.targetClass);
//        while (res.hasNext()) {               
//            Resource instance = res.nextResource();                        
//            NodeIterator ni = this.model.listObjectsOfProperty(instance, SDTLearner.TARGETPROPERTY);
//            while (ni.hasNext()) {
//                RDFNode value = ni.nextNode();
//                if (!valueSet.contains(value)) {
//                    valueSet.add(value);
//                }
//                this.targetinstSet.put(instance, valueSet.indexOf(value));
//            }
//        }
//
//        SDTLearner.TARGETVALUESIZE = valueSet.size();
//        this.targetinstSet.setTargetInstanceValueSet(valueSet);
//        this.targetinstSet.printTargetInstanceSet();
//
//        this.instanceSet = this.targetinstSet.getInstance();
//        this.root = new DNode(this.instanceSet, "Root");
////        this.targetinstSet.printTargetInstanceSet();
//        this.ur = new UncountedResources();
    }

    @Deprecated
    public SDTLearner(String targetClass, Vector<Resource> positiveInstance, Vector<Resource> negativeInstance, OntologyModel ontmodel, int learningOption) {
//        this.model = ontmodel.getJenaModel();
//        this.learningOption = learningOption;
//        this.targetClass = model.getResource(targetClass);
//        this.classmodel = new ClassModel();
//        this.classmodel.classModelMaker(model);
//        this.ners = new DecisionRuleSet();
//        this.targetinstSet = new TargetInstanceSet(positiveInstance, negativeInstance);
//        this.instanceSet = this.targetinstSet.getInstance();
//        this.root = new DNode(this.instanceSet, "Root");
//        this.ur = new UncountedResources();
    }

    public SDTLearner(Vector<Resource> positiveInstance, Vector<Resource> negativeInstance, OntologyModel ontmodel, int learningOption) {
//        this.model = ontmodel.getJenaModel();
//        this.learningOption = learningOption;
//        this.classmodel = new ClassModel();
//        this.classmodel.classModelMaker(model);
//        this.ners = new DecisionRuleSet();
//        this.targetinstSet = new TargetInstanceSet(positiveInstance, negativeInstance);
//        this.instanceSet = this.targetinstSet.getInstanceList();
//        this.root = new DNode(this.instanceSet, "Root");
//        this.ur = new UncountedResources();
    }

    public DNode learningStart(boolean nontargetclass) {

//        dcs = new DecomposeCandidateSet();
//        DCSSearcher sdcs = new DCSSearcher(this.model, this.classmodel, this.learningOption);
//        TreeDecomposer td = new TreeDecomposer(this.model, this.classmodel, this.learningOption, this.targetinstSet, this.ENTROPY_THRESHOLD);
//
//        long startTime = System.currentTimeMillis();
//
//        sdcs.searchDecomposeCandidateSet(dcs, this.instanceSet, new Vector<PropertyArc>());
//        this.root.setTargetValueInstanceInformation(targetinstSet);
//        this.root.setEntropy();
//
//        td.decomposeTreeNode(this.root, dcs);
//
//        long endTime = System.currentTimeMillis();
//        System.out.println("\nRunning Time = " + (endTime - startTime) / 1000.0f + " sec");
//        td.setinit();
////        dcs.printDecomposeCandidateSet();
//
//        SDTLog.log(SDTLog.BASIC, root.toString());
//        this.printNode(this.root);
//
////        SDTSearcher sdts = new SDTSearcher(this.model);
////        DecisionRuleSet drs = this.getDecisionRuleSet();
////        
////        for (int i = 0; i < drs.size(); i++) {
////            System.out.println("-----------------------------------------------------------------------");
////            DecisionRule dr = drs.get(i);            
////            Vector<Resource> resultset = sdts.getRuleMatcherInstanceSet(dr, new Vector<Resource>());
////            
////        }

        return this.root;
    }

    public void setENTROPY_THRESHOLD(double d) {
        this.ENTROPY_THRESHOLD = d;
    }

    public DecisionRuleSet getDecisionRuleSet() {
        if (this.ners.isEmpty()) {
            generateDecisionRuleSet(this.root, new DecisionRule());
        }
        return this.ners;
    }

    private void generateDecisionRuleSet(DNode node, DecisionRule olddr) {
        for (int i = 0; i < node.getEdge().size(); i++) {
            DEdge edge = node.getEdge().get(i);
            DecisionRuleComponent drc = new DecisionRuleComponent(edge.getRefinement());
            DecisionRule newdr = new DecisionRule(olddr, drc);
            this.ners.add(newdr);
            if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
                generateDecisionRuleSet(edge.getChildNode(), newdr);
            }
        }
    }

    public void setLearningOption(int option) {
        this.learningOption = option;
    }

    public void printNode(DNode node) {
//        String s = new String();        
        for (int i = 0; i < node.getEdge().size(); i++) {
            DEdge edge = node.getEdge().get(i);

            SDTLog.log(SDTLog.BASIC, edge.toString());

//            edge.getChildNode().setRuleComposer(node.getRuleComposer(), edge.getRefinement());  // rule generate

            if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
                SDTLog.log(SDTLog.BASIC, edge.getChildNode().toString());
                printNode(edge.getChildNode());
            } else {
                SDTLog.log(SDTLog.BASIC, edge.getChildNode().toString());
            }
        }
    }
    
    public void showTree(DNode node){
        GDLearningPanel gdp = new GDLearningPanel(new GraphDataLearner());
        gdp.main(node);
    }
}
